package com.june.filewatch;

import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.WatchEvent.Kind;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * 用于遍历文件夹并监控文件夹
 * @author June
 */
public class FileVisitor extends SimpleFileVisitor<Path> implements Runnable{
	private WatchService watcher;
	private Kind<Path>[] mask;
	private FileListener fileListener;
	private Map<WatchKey,Path> watchKeyPath;
	private boolean watchSubTree;
	private boolean dirListener;
	private boolean isStop;
	public FileVisitor(boolean watchSubTree,boolean dirListener,Map<WatchKey,Path> watchKeyPath,WatchService watcher,Kind<Path>[] mask,FileListener fileListener) throws InterruptedException, IOException{
		this.watcher = watcher;
		this.mask = mask;
		this.fileListener = fileListener;
		this.watchKeyPath = watchKeyPath; 
		this.watchSubTree = watchSubTree;
		this.dirListener = dirListener;
		this.isStop = false;
	}
	@Override
	public FileVisitResult postVisitDirectory(Path dir, IOException exc)
			throws IOException {
		WatchKey watchKey = dir.register(watcher, mask);
		watchKeyPath.put(watchKey, dir);
		return super.postVisitDirectory(dir, exc);
	}
	@Override
	public void run() {
		while(!isStop){
			try {
				WatchKey key = watcher.take();//阻塞式方式查询发生的事件
				for (WatchEvent<?> event : key.pollEvents()) {
					Path p = (Path)event.context();
					p = watchKeyPath.get(key).resolve(p);//得到完整路径
					Method m;
					if(event.kind().equals(FileEvent.FILE_CREATE)){
						if(Files.isDirectory(p)){
							//新建了一个文件夹
							//递归监控新建的文件夹
							if(watchSubTree)
								Files.walkFileTree(p, this);
							if(!dirListener){
								//不响应文件夹上的事件
								break;
							}
						}
						m = fileListener.getClass().getMethod("createListener", Path.class);
						m.setAccessible(true);
						m.invoke(fileListener,p);
					}else if(event.kind().equals(FileEvent.FILE_DELETE)){
						m = fileListener.getClass().getMethod("deleteListener", Path.class);
						m.setAccessible(true);
						m.invoke(fileListener,p);
						deleteWatchKeyPath(watchKeyPath);
					}else if(event.kind().equals(FileEvent.FILE_MODIFY)){
						if(Files.isDirectory(p)&&(!dirListener)){
							//文件夹的修改
							//不响应文件夹上的事件
						}else{
							m = fileListener.getClass().getMethod("modifyListener", Path.class);
							m.setAccessible(true);
							m.invoke(fileListener,p);
						}
					}
				}
				key.reset();//只有在重置之后，新产生的同类事件才有可能从WatchService接口实现对象中再次获取
			} catch (Exception e) {
				System.out.println(e.getMessage());
			}
		}
	}
	/**
	 * 删除Path不存在的watchKey
	 * @author June
	 * @param watchKeyPath
	 */
	private void deleteWatchKeyPath(Map<WatchKey, Path> watchKeyPath) {
		Set<WatchKey> set = watchKeyPath.keySet();
		Iterator<WatchKey> it = set.iterator();
		while(it.hasNext()){
			WatchKey key = it.next();
			Path p = watchKeyPath.get(key);
			if(!p.toFile().exists()){
				watchKeyPath.remove(key);
			}
		}
	}
	public synchronized void setStop() {
		this.isStop = true;
	}
}
